package heap

import (
	"encoding/json"
	"fmt"
	"game/readygo/util"
	"reflect"
	"sync"
	"time"
)

type HeapCache[T interface{}] struct {
	cache           sync.Map   //缓存
	relationFields  []string   //缓存存储的关系字段
	aliveTime       int64      //节点的存活时长，0表示不会过期
	firstExpireTime int64      //最早过期的时间
	rootLock        sync.Mutex //缓存的锁
}

func CreateHeapCache[T interface{}](relationFields []string, aliveTime int64) *HeapCache[T] {
	var heapCache HeapCache[T]
	heapCache.relationFields = relationFields
	heapCache.aliveTime = aliveTime
	return &heapCache
}

func (t *HeapCache[T]) Add(entities ...T) {
	for _, entity := range entities {
		t.add(entity)
	}
}

func (t *HeapCache[T]) add(entity T) {
	rField := reflect.ValueOf(entity).Elem().FieldByName(t.relationFields[0])
	key := fmt.Sprintf("%v", rField.Interface())

	root0, ok := t.cache.Load(key)
	if !ok {
		root0 = t.initRoot(t.relationFields[0], key)
	}
	root := root0.(*cacheRoot)

	root.lock.Lock()
	defer root.lock.Unlock()

	t.addNode(entity, root, 1)
	root.lastAccessTime = time.Now().UnixMilli()
}

func (t *HeapCache[T]) CreateEmptyRoot(firstKey interface{}) {
	t.initRoot(t.relationFields[0], fmt.Sprintf("%v", firstKey))
}

func (t *HeapCache[T]) initRoot(fieldName string, cacheKey string) *cacheRoot {
	t.rootLock.Lock()
	defer t.rootLock.Unlock()

	root0, ok := t.cache.Load(cacheKey)
	if ok {
		return root0.(*cacheRoot)
	}
	var cacheRoot cacheRoot
	cacheRoot.parent = nil
	cacheRoot.fieldName = fieldName
	cacheRoot.keyValue = cacheKey
	cacheRoot.lastAccessTime = time.Now().UnixMilli()
	t.cache.Store(cacheKey, &cacheRoot)
	return &cacheRoot
}

func (t *HeapCache[T]) addNode(entity T, parentNode icacheNode, fieldIndex int) {
	if fieldIndex >= len(t.relationFields) {
		if parentNode.getEntity() != nil {
			currNode := parentNode
			msg := ""
			for currNode != nil {
				msg = fmt.Sprintf(" (%s=%s)", currNode.getFieldName(), currNode.getKeyValue()) + msg
				currNode = currNode.getParent()
			}
			msg = fmt.Sprintf("duplicate entity try to add to the cache, className = %s with ", reflect.TypeOf(entity).Name()) + msg
			panic(msg)
		}
		parentNode.setEntity(entity)
	} else {
		fieldName := t.relationFields[fieldIndex]
		rField := reflect.ValueOf(entity).Elem().FieldByName(fieldName)
		keyValue := fmt.Sprintf("%v", rField.Interface())
		parentNode.initCache()
		childNode := parentNode.getChild(keyValue)
		if childNode == nil {
			var cacheNode cacheNode
			cacheNode.parent = parentNode
			cacheNode.fieldName = fieldName
			cacheNode.keyValue = keyValue
			childNode = &cacheNode
			parentNode.addChild(childNode)
		}
		t.addNode(entity, childNode, fieldIndex+1)
	}
}

func (t *HeapCache[T]) GetAll() []T {
	results := make([]T, 0)
	t.cache.Range(func(key any, value any) bool {
		root := value.(*cacheRoot)
		results = t.getInNode(results, root)
		return true
	})
	return results
}

func (t *HeapCache[T]) getInNode(results []T, node icacheNode) []T {
	if node.getEntity() != nil {
		results = append(results, node.getEntity().(T))
	}
	if node.getChildNodes() != nil {
		for _, child := range node.getChildNodes() {
			results = t.getInNode(results, child)
		}
	}
	return results
}

func (t *HeapCache[T]) Get(keys ...interface{}) (T, bool) {
	resultList := t.GetList(keys...)
	if resultList == nil {
		var t T
		return t, false
	}
	if len(resultList) > 1 {
		panic(fmt.Sprintf("result set of keys %v more than one", keys))
	} else if len(resultList) == 1 {
		return resultList[0], true
	} else {
		var t T
		return t, false
	}
}

func (t *HeapCache[T]) GetList(keys ...interface{}) []T {
	keySize := len(keys)
	if keySize <= 0 {
		panic("attemp to find empty keys")
	}
	if keySize > len(t.relationFields) {
		panic(fmt.Sprintf("cache deep %v, but want to get deep %v", len(t.relationFields), keySize))
	}
	t.checkExpire()

	key := fmt.Sprintf("%v", keys[0])
	root0, ok := t.cache.Load(key)
	if !ok {
		return nil
	}
	root := root0.(*cacheRoot)
	root.lock.Lock()
	defer root.lock.Unlock()

	resultList := make([]T, 0)
	node := icacheNode(root)
	for i := 1; i <= keySize; i++ {
		if i == keySize {
			resultList = t.fillList(resultList, node)
		} else {
			node = node.getChild(fmt.Sprintf("%v", keys[i]))
			if node == nil {
				break
			}
		}
	}
	root.lastAccessTime = time.Now().UnixMilli()
	return resultList
}

func (t *HeapCache[T]) checkExpire() {
	if t.aliveTime <= 0 {
		return
	}
	nowTime := time.Now().UnixMilli()
	if nowTime < t.firstExpireTime {
		return
	}
	t.rootLock.Lock()
	defer t.rootLock.Unlock()

	nextExpireTime := nowTime + t.aliveTime
	t.cache.Range(func(key any, value any) bool {
		root := value.(*cacheRoot)
		expireTime := root.lastAccessTime + t.aliveTime
		if nowTime >= expireTime {
			//会不会导致遍历中修改？
			t.deleteRoot(root.getKeyValue())
		}
		if expireTime < nextExpireTime {
			nextExpireTime = expireTime
		}
		return true
	})
	t.firstExpireTime = nextExpireTime
}

func (t *HeapCache[T]) fillList(resultList []T, node icacheNode) []T {
	if node.getChildList() == nil {
		if node.getEntity() != nil {
			//为了避免缓存击穿，在查询不到数据时会添加空的根节点，其中的entity等于null
			resultList = append(resultList, node.getEntity().(T))
		}
	} else {
		for _, child := range node.getChildList() {
			resultList = t.fillList(resultList, child)
		}
	}
	return resultList
}

func (t *HeapCache[T]) Has(firstKey interface{}) bool {
	_, ok := t.cache.Load(fmt.Sprintf("%v", firstKey))
	return ok
}

func (t *HeapCache[T]) Delete(entities ...T) {
	for _, entity := range entities {
		t.delete(entity)
	}
}

func (t *HeapCache[T]) delete(entity T) {
	fieldName := t.relationFields[0]
	rValue := reflect.ValueOf(entity).Elem()
	key := fmt.Sprintf("%v", rValue.FieldByName(fieldName).Interface())
	root0, ok := t.cache.Load(key)
	if !ok {
		return
	}
	root := root0.(*cacheRoot)
	root.lock.Lock()
	defer root.lock.Unlock()

	node := icacheNode(root)
	for i := 1; i <= len(t.relationFields); i++ {
		if node.getEntity() != nil {
			if node.getKeyValue() == key {
				node.setEntity(nil)
				if node.getParent() != nil {
					node.getParent().deleteNode(key)
				}
				node = node.getParent()
				break
			}
		} else {
			fieldName = t.relationFields[i]
			key = fmt.Sprintf("%v", rValue.FieldByName(fieldName).Interface())

			node = node.getChild(key)
			if node == nil {
				return
			}
		}
	}
	currNode := node
	for currNode != nil {
		if !currNode.isEmpty() {
			break
		}
		parent := currNode.getParent()
		if parent != nil {
			parent.deleteNode(currNode.getKeyValue())
		} else {
			t.deleteRoot(currNode.getKeyValue())
		}
		currNode = parent
	}
}

func (t *HeapCache[T]) deleteRoot(key string) {
	t.cache.Delete(key)
}

// 缓存的情况
func (t *HeapCache[T]) Sprint() string {
	buffer := util.NewCodeBuffer()
	t.cache.Range(func(key any, value any) bool {
		printNode(buffer, value.(*cacheRoot), "")
		return true
	})
	return buffer.ToString()
}

func printNode(buffer *util.CodeBuffer, node icacheNode, tab string) {
	bytes, err := json.Marshal(node.getEntity())
	if err != nil || node.getEntity() == nil {
		buffer.Nformat("%s%s:%s=%s, entity=null, data=null", tab, node.getKeyValue(), node.getFieldName(), node.getKeyValue())
	} else {
		buffer.Nformat("%s%s:%s=%s, entity=%p, data=%s", tab, node.getKeyValue(), node.getFieldName(), node.getKeyValue(), node.getEntity(), string(bytes))
	}
	if node.getChildNodes() != nil {
		buffer.Format(", cacheSize=%v, cacheMap=", len(node.getChildNodes()))
		for _, child := range node.getChildNodes() {
			printNode(buffer, child, tab+util.TAB)
		}
	}
}

type icacheNode interface {
	getFieldName() string
	getKeyValue() string
	getChildNodes() map[string]icacheNode
	getChildList() []icacheNode
	getEntity() interface{}
	setEntity(entity interface{})
	getParent() icacheNode
	initCache()
	getChild(key string) icacheNode
	addChild(child icacheNode)
	deleteNode(key string)
	isEmpty() bool
}

type cacheNode struct {
	fieldName  string
	keyValue   string
	entity     interface{}
	childNodes map[string]icacheNode
	childList  []icacheNode
	inited     bool       //是否已经初始化
	parent     icacheNode //父节点
}

func (t *cacheNode) getFieldName() string {
	return t.fieldName
}
func (t *cacheNode) getKeyValue() string {
	return t.keyValue
}
func (t *cacheNode) getChildNodes() map[string]icacheNode {
	return t.childNodes
}
func (t *cacheNode) getEntity() interface{} {
	return t.entity
}
func (t *cacheNode) setEntity(entity interface{}) {
	t.entity = entity
}
func (t *cacheNode) getParent() icacheNode {
	return t.parent
}

func (t *cacheNode) initCache() {
	if t.inited {
		return
	}
	t.childNodes = make(map[string]icacheNode)
	t.childList = make([]icacheNode, 0)
	t.inited = true
}
func (t *cacheNode) getChild(key string) icacheNode {
	if t.childNodes == nil {
		return nil
	}
	child := t.childNodes[key]
	return child
}
func (t *cacheNode) addChild(child icacheNode) {
	t.childNodes[child.getKeyValue()] = child
	t.childList = append(t.childList, child)
}
func (t *cacheNode) getChildList() []icacheNode {
	return t.childList
}
func (t *cacheNode) deleteNode(key string) {
	_, ok := t.childNodes[key]
	if ok {
		delete(t.childNodes, key)
		indexToRemove := -1
		for i, child := range t.childList {
			if child.getKeyValue() == key {
				indexToRemove = i
				break
			}
		}
		if indexToRemove != -1 {
			t.childList = append(t.childList[:indexToRemove], t.childList[indexToRemove+1:]...)
		}
	}
}
func (t *cacheNode) isEmpty() bool {
	if t.childList == nil {
		return false
	}
	return len(t.childList) <= 0
}

type cacheRoot struct {
	cacheNode
	lastAccessTime int64 //最后访问时间
	lock           sync.Mutex
}
